//
//  RxSwiftErrorDebugViewController.swift
//  DemoProject
//
//  Created by Hao on 2018/8/8.
//  Copyright © 2018年 hao. All rights reserved.
//

import UIKit

fileprivate enum RxSwiftError : Error {
    
    case A
    case B
    
    var localizedDescription: String {
        switch self {
        case .A:
            return "ErrorA_Info"
        case .B:
            return "ErrorB_Info"
        }
    }
    
//    func info() -> String {
//        switch self {
//        case .A:
//            return "ErrorA_Info"
//        case .B:
//            return "ErrorB_Info"
//        }
//    }
}

/// 错误处理、调试操作
class RxSwiftErrorDebugViewController: BaseViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
//        testRxSwiftError()
        testRxSwiftDebugging()
    }

}

// MARK: 错误处理操作（Error Handling Operators）
extension RxSwiftErrorDebugViewController {
    
    fileprivate func testRxSwiftError() {
//        _catchErrorJustReturn()
//        _catchError()
        _retry()
    }
    
    /// 当遇到 error 事件的时候，就返回指定的值，然后结束
    /// 运行结果:
    ///    next(1)
    ///    next(2)
    ///    next(错误信息)
    ///    completed
    private func _catchErrorJustReturn() {
        let disposeBag = DisposeBag()
        let sequenceFails = PublishSubject<String>()
        sequenceFails.catchErrorJustReturn("错误信息").subscribe { print(info: $0) }.disposed(by: disposeBag)
        
        sequenceFails.onNext("1")
        sequenceFails.onNext("2")
        sequenceFails.onError(RxSwiftError.A)
        sequenceFails.onNext("3")
    }
    
    /// 该方法可以捕获 error，并对其进行处理。
    /// 同时还能返回另一个 Observable 序列进行订阅（切换到新的序列）
    /// 运行结果:
    ///    next(a)
    ///    next(b)
    ///    Error: A
    ///    next(1)
    ///    next(2)
    ///    completed
    private func _catchError() {
        let disposeBag = DisposeBag()
        let sequenceFails = PublishSubject<String>()
        let recoverySequence = Observable.of("1", "2")
        
        sequenceFails.catchError {
//            (error) -> Observable<String> in
//            print(info: "Error: \((error as! RxSwiftError).localizedDescription)")
            print(info: "Error: \($0)")
            return recoverySequence
        }.subscribe { print(info: $0) }.disposed(by: disposeBag)
        
        sequenceFails.onNext("a")
        sequenceFails.onNext("b")
        sequenceFails.onError(RxSwiftError.A)
        sequenceFails.onNext("c")
    }
    
    /// 使用该方法当遇到错误的时候，会重新订阅该序列。比如遇到网络请求失败时，可以进行重新连接
    /// retry() 方法可以传入数字表示重试次数。不传的话只会重试一次
    /// 运行结果:
    ///    next(a)
    ///    next(b)
    ///    Error encountered
    ///    next(a)
    ///    next(b)
    ///    next(c)
    ///    next(d)
    private func _retry() {
        let disposeBag = DisposeBag()
        var count = 1
        // .create 闭包可简写为 { observer in }
        let sequenceErrors = Observable<String>.create { (observer) -> Disposable in
            observer.onNext("a")
            observer.onNext("b")
            
            if count == 1 {
                observer.onError(RxSwiftError.A)
                print(info: "Error encountered")
                count += 1
            }
            
            observer.onNext("c")
            observer.onNext("d")
            
            return Disposables.create()
        }
        
        // 重试两次 (参数为空则只试一次)
        sequenceErrors.retry().subscribe { print(info: $0) }.disposed(by: disposeBag)
    }
    
}

// MARK: 调试操作
extension RxSwiftErrorDebugViewController {
    
    fileprivate func testRxSwiftDebugging() {
        _debug()
    }
    
    /// 将 debug 调试操作符添加到一个链式步骤当中，这样系统就能将所有的订阅者、事件、和处理等详细信息打印出来，方便我们开发调试
    /// 运行结果:
    ///    (_debug()) -> subscribed
    ///    (_debug()) -> Event next(1)
    ///    1
    ///    (_debug()) -> Event next(2)
    ///    2
    ///    (_debug()) -> Event next(3)
    ///    3
    ///    (_debug()) -> Event completed
    ///    (_debug()) -> isDisposed
    private func _debug() {
        let disposeBag = DisposeBag()
        
        Observable.of("2", "3")
            .startWith("1")
        /// debug() 方法还可以传入标记参数，这样当项目中存在多个 debug 时可以很方便地区分出来 debug("RxSwift_Debug")
            .debug()
            .subscribe(onNext: { print(info: $0) })
            .disposed(by: disposeBag)
    }
    
    /// 通过将 RxSwift.Resources.total 打印出来，我们可以查看当前 RxSwift 申请的所有资源数量。这个在检查内存泄露的时候非常有用
    private func _resourcesTotal() {
//        RxSwift.Reactive;
//        print(info: RxSwift.Resources.total)
//
//        let disposeBag = DisposeBag()
//
//        print(info: RxSwift.Resources.total)
//
//        Observable.of("BBB", "CCC")
//            .startWith("AAA")
//            .subscribe(onNext: { print($0) })
//            .disposed(by: disposeBag)
//
//        print(info: RxSwift.Resources.total)
    }
    
}




